package com.benzhuo.widget.research.recycler;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import com.benzhuo.widget.research.R;

import java.lang.ref.WeakReference;

/**
 * 实现了RecyclerView 自动加载更多的功能
 * Created by WuWangchun on 2016/7/20.
 */
public class ZLoadRecyclerView extends RecyclerView {
    //加载更多监听
    private ILoadMoreListener loadMoreListener;
    //加载更多视图
    private View loadMoreView;
    //是否能够设置加载更多View的状态，即是否实现了LoadState接口
    private boolean canSetLoadMoreViewState;

    private ZAdapter zAdapter;

    private Handler handler = new MyHandler(this);

    private boolean isLoading = false;//是否在加载数据

    private boolean noMore = false;//没有更多数据

    //判断是否是向上滑动
    private float startY;//TouchDown时的Y值
    private float startX;//TouchDown时的X值
    private float moveDx;//X方向移动距离
    private float moveDy;//Y方向移动距离
    private boolean singleTouch;//是否是单指

    public ZLoadRecyclerView(Context context) {
        super(context);
        init();
    }

    public ZLoadRecyclerView(Context context,  AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ZLoadRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public boolean isLoading() {
        return isLoading;
    }

    protected void setLoading(boolean loading) {
        isLoading = loading;
    }

    private void init(){
        zAdapter = new ZAdapter();
        if (getLayoutManager()!=null){
            zAdapter.setLayoutManager(getLayoutManager());
        }
        ZGifLoadMoreView load = new ZGifLoadMoreView(getContext());
        load.setBitmapResource(R.drawable.load_more);
        load.setText("正在加载","加载失败","没有更多数据");
        setLoadMoreView(load);
        this.addOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                //TODO 横向时判断DX
                if (!singleTouch||moveDy>=0||noMore){
                    return;
                }
                if(newState == RecyclerView.SCROLL_STATE_IDLE || loadMoreView != null){
                    LayoutManager layoutManager = getLayoutManager();
                    int lastItemPosition = 0;
                    if (layoutManager instanceof LinearLayoutManager){
                       lastItemPosition = ((LinearLayoutManager)layoutManager).findLastVisibleItemPosition();
                    }else if (layoutManager instanceof GridLayoutManager){
                        lastItemPosition = ((GridLayoutManager)layoutManager).findLastVisibleItemPosition();
                    }else if (layoutManager instanceof StaggeredGridLayoutManager){
                        StaggeredGridLayoutManager lm = (StaggeredGridLayoutManager)layoutManager;
                        int[] into = new int[lm.getSpanCount()];
                        lm.findLastVisibleItemPositions(into);
                        for (int i : into){
                            lastItemPosition = lastItemPosition>i?lastItemPosition:i;
                        }
                    }
                    if(layoutManager.getChildCount()>0 && lastItemPosition>=layoutManager.getItemCount()-1){
                        //Loading the more data
                        if (!isLoading){
                            loadMoreView.setVisibility(VISIBLE);
                            if (canSetLoadMoreViewState){
                                ((ILoadStateSet)loadMoreView).beginLoading();
                            }
                            loadMoreListener.loadMore(ZLoadRecyclerView.this);
                        }
                    }
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                Log.d("scroll","dx:"+dx+"     dy:"+dy);
            }
        });
    }

    private void setLoadFinish(ILoadStateSet.State state){
        if (canSetLoadMoreViewState){
            ILoadStateSet stateSet = (ILoadStateSet)loadMoreView;
            int time = stateSet.stopLoading(state);
            if (time>0){
                if (state== ILoadStateSet.State.LOAD_NO_MORE){
                    handler.sendEmptyMessageDelayed(1,time);
                }else if (state== ILoadStateSet.State.LOAD_FAIL){
                    handler.sendEmptyMessageDelayed(3,time);
                }else {
                    handler.sendEmptyMessageDelayed(2,time);
                }
            }else {
                loadFinished();
            }
        }else {
            loadFinished();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:{
                startX =ev.getX();
                startY =ev.getY();
                moveDx=0;
                moveDy=0;
                singleTouch=true;
            }break;
            case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_UP:
                // 过滤多点触碰
                singleTouch=false;
                break;
            case MotionEvent.ACTION_MOVE:{
                if (singleTouch){
                    moveDx=ev.getX()- startX;
                    moveDy=ev.getY()- startY;
                }
            }break;
            case MotionEvent.ACTION_UP:{
                if (singleTouch){
                    moveDx=ev.getX()- startX;
                    moveDy=ev.getY()- startY;
                }
            }break;
        }
        return super.dispatchTouchEvent(ev);
    }

    private void loadFinished(){
        loadMoreView.setVisibility(INVISIBLE);
        isLoading=false;
    }

    public void loadFail(){
       setLoadFinish(ILoadStateSet.State.LOAD_FAIL);
    }

    public void loadSuccess(){
       setLoadFinish(ILoadStateSet.State.LOAD_SUCCESS);
    }

    public void loadNoMoreData(){
        setLoadFinish(ILoadStateSet.State.LOAD_NO_MORE);
    }

    public boolean isNoMore() {
        return noMore;
    }

    public void setNoMore(boolean noMore) {
        if (this.noMore==noMore){
            return;
        }
        this.noMore = noMore;
        if (noMore==true){
            zAdapter.notifyItemRemoved(zAdapter.getItemCount());
        }else {
            if (canSetLoadMoreViewState){
                ((ILoadStateSet)loadMoreView).beginLoading();
            }
        }
    }

    @Override
    public void setAdapter(Adapter adapter) {
        zAdapter.setAdapter(adapter);
        super.setAdapter(zAdapter);
    }

    @Override
    public void setLayoutManager(LayoutManager layout) {
        super.setLayoutManager(layout);
        if (zAdapter!=null){
            zAdapter.setLayoutManager(layout);
        }
    }

    @Override
    public Adapter getAdapter() {
        return zAdapter.getAdapter();
    }

    public View getLoadMoreView() {
        return loadMoreView;
    }

    public void setLoadMoreView(View loadMoreView) {
        this.loadMoreView = loadMoreView;
        zAdapter.setFootView(loadMoreView);
        loadMoreView.setVisibility(INVISIBLE);
        if(loadMoreView instanceof ILoadStateSet){
            canSetLoadMoreViewState = true;
        }else {
            canSetLoadMoreViewState = false;
        }
    }

    public ILoadMoreListener getLoadMoreListener() {
        return loadMoreListener;
    }

    public void setLoadMoreListener(ILoadMoreListener loadMoreListener) {
        this.loadMoreListener = loadMoreListener;
    }

    //Load状态接口
    public interface ILoadStateSet {
        enum State{
            LOAD_SUCCESS,
            LOAD_FAIL,
            LOAD_NO_MORE
        }
        void beginLoading();

        /**
         * 数据加载完成
         * @param state 加载结果 @see State
         * @return 停留时间，单位毫秒
         */
        int stopLoading(State state);
    }

    public interface ILoadMoreListener {
        void loadMore(final ZLoadRecyclerView recyclerView);
    }

    private class ZAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        private static final int FOOTER = -1;
        private RecyclerView.Adapter adapter;
        private View footView;
        LayoutManager layoutManager;
        private void setLayoutManager(LayoutManager manager){
            this.layoutManager=manager;
            if (manager instanceof GridLayoutManager) {
                final GridLayoutManager gridManager = ((GridLayoutManager) manager);
                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        if (isFooter(position)) {
                            return gridManager.getSpanCount();
                        }else {
                            return 1;
                        }
                    }
                });
            }
        }

        public Adapter getAdapter() {
            return adapter;
        }

        public void setAdapter(Adapter adapter) {
            this.adapter = adapter;
            adapter.registerAdapterDataObserver(new AdapterDataObserver() {
                @Override
                public void onChanged() {
                    super.onChanged();
                    zAdapter.notifyDataSetChanged();
                }

                @Override
                public void onItemRangeChanged(int positionStart, int itemCount) {
                    super.onItemRangeChanged(positionStart, itemCount);
                    zAdapter.notifyItemRangeChanged(positionStart,itemCount);
                }

                @Override
                public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
                    super.onItemRangeChanged(positionStart, itemCount, payload);
                    zAdapter.notifyItemRangeChanged(positionStart,itemCount,payload);
                }

                @Override
                public void onItemRangeInserted(int positionStart, int itemCount) {
                    super.onItemRangeInserted(positionStart, itemCount);
                    zAdapter.notifyItemRangeInserted(positionStart,itemCount);
                }

                @Override
                public void onItemRangeRemoved(int positionStart, int itemCount) {
                    super.onItemRangeRemoved(positionStart, itemCount);
                    zAdapter.notifyItemRangeRemoved(positionStart,itemCount);
                }

                @Override
                public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
                    super.onItemRangeMoved(fromPosition, toPosition, itemCount);
                    zAdapter.notifyItemRangeRemoved(fromPosition,itemCount);
                }
            });
        }

        public View getFootView() {
            return footView;
        }

        public void setFootView(View footView) {
            this.footView = footView;
        }

        @Override
        public int getItemCount() {
            if (noMore){
                if (adapter == null){
                    return 0;
                }
                return adapter.getItemCount();
            }else {
                if (adapter == null){
                    return 1;
                }
                return adapter.getItemCount()+1;
            }
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if(viewType==FOOTER) {
                ViewParent vp = footView.getParent();
                if (vp!=null&&vp instanceof ViewGroup){
                    ((ViewGroup) vp).removeView(footView);
                }
                return new ViewHolder(footView);
            }
            return adapter.onCreateViewHolder(parent,viewType);
        }

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            if (noMore||position<getItemCount()-1){
                adapter.onBindViewHolder(holder,position);
            }
        }

        @Override
        public int getItemViewType(int position) {
            if (noMore){
                return adapter.getItemViewType(position);
            }
            if(adapter==null){
                return FOOTER;
            }
            if(position==adapter.getItemCount()) {
                return FOOTER;
            }
            return adapter.getItemViewType(position);
        }

        @Override
        public long getItemId(int position) {
            if (noMore){
                return adapter.getItemId(position);
            }
            if(adapter==null){
                return FOOTER;
            }
            if(position==adapter.getItemCount()) {
                return FOOTER;
            }
            return adapter.getItemId(position);
        }

        @Override
        public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if (lp != null)
                if (isFooter(holder.getLayoutPosition())){
                    if (lp instanceof StaggeredGridLayoutManager.LayoutParams){
                        StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
                        p.setFullSpan(true);
                    }
                    if (getOrientation()==OrientationHelper.HORIZONTAL){
                        lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
                    }else {
                        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
                    }
                }
        }

        private int getOrientation(){
            if (layoutManager instanceof LinearLayoutManager){
               int o = ((LinearLayoutManager)layoutManager).getOrientation();
                return o==LinearLayoutManager.HORIZONTAL?OrientationHelper.HORIZONTAL:OrientationHelper.VERTICAL;
            }else if (layoutManager instanceof StaggeredGridLayoutManager){
                int o = ((StaggeredGridLayoutManager)layoutManager).getOrientation();
                return o==StaggeredGridLayoutManager.HORIZONTAL? OrientationHelper.HORIZONTAL:OrientationHelper.VERTICAL;
            }
            return OrientationHelper.HORIZONTAL;
        }

        /**
         * 当前布局是否为Footer
         *
         * @param position
         * @return
         */
        public boolean isFooter(int position) {
            if (noMore){
                return false;
            }
            return position < getItemCount() && position >= getItemCount() - 1;
        }

        public class ViewHolder extends RecyclerView.ViewHolder{
            public ViewHolder(View itemView) {
                super(itemView);
            }
        }
    }

    private class MyHandler extends Handler {
        WeakReference<ZLoadRecyclerView> oneRef;

        public MyHandler(ZLoadRecyclerView one) {
            this.oneRef = new WeakReference<ZLoadRecyclerView>(one);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            ZLoadRecyclerView recyclerView = oneRef.get();
            if (recyclerView==null){
                return;
            }
            switch (msg.what){
                case 1:{
                    recyclerView.loadFinished();
                    setNoMore(true);
                }break;
                case 2:{
                    recyclerView.loadFinished();
                }break;
                case 3:{
                    recyclerView.loadFinished();
                    scrollBy(0,-loadMoreView.getHeight());
                }break;
            }
        }
    }
}
